#include"ThreadPool.h"

ThreadPool::ThreadPool(int min, int max):m_minThread(min),m_maxThread(max),m_stop(false),
m_idleThread(min),m_curThread(min)
{

    // 创建管理者线程
    // 如果是类里面的成员函数，这里需要加  所有者 , 也就是this
    m_manager=new thread(&ThreadPool::manager,this);
    for(int i=0;i<min; ++i){
        // thread t(&ThreadPool::woker,this);
        // m_workers.push_back(t);   //push_back 会复制然后放入vector,浪费效率
        // m_workers.emplace_back(t);   //emplace_back 不发生拷贝，所以需要传入非临时对象
        thread t(&ThreadPool::worker,this);
        //注意线程对象不允许拷贝。 thread(const thread&)=delete
        m_workers.insert(make_pair(t.get_id(), move(t))); //匿名对象，在从容器中弹出时候销毁！
    }
} 


ThreadPool::~ThreadPool(){
    m_stop=true;
    //唤醒所有阻塞在条件变量上的线程
    m_condition.notify_all();
    for(auto& it:m_workers){     //线程对象不允许拷贝
        thread& t = it.second;
        if(t.joinable()){  //可连接
            cout<<"************ Thread "<<t.get_id()<<" will destory"<<endl;
            t.join();
        }
    }
    if(m_manager->joinable()){
        m_manager->join();
    }
    delete m_manager;
}

// void ThreadPool::addTask(function<void(void)> task){
//     {
//         lock_guard<mutex> locker(m_queueMutex);
//         m_tasks.emplace(task);
//     }
//     //这里不上锁
//     m_condition.notify_one(); //唤醒1个
// }

void ThreadPool::manager(void){

    while(!m_stop.load()){
        //当前线程睡眠  chrono库描述时间
        this_thread::sleep_for(chrono::seconds(1)); 
        int idel = m_idleThread;
        int cur  = m_curThread;
        //空闲的线程大于当前线程的一半，=> 空闲的现线程太多
        if(idel > cur/2 && cur > m_minThread){
            //每次销毁2个线程
            m_exitThread.store(2);
            m_condition.notify_all();
            lock_guard<mutex> lock(m_idsMutex);
            for(auto id:m_ids){
                //检查键是否存在
                auto it = m_workers.find(id);
                if(it != m_workers.end()){
                    
                    cout<<"====== Thread "<<(*it).first<<"  Destroyed ..."<<endl;
                    //阻塞
                    (*it).second.join();
                    m_workers.erase(it);
                }
            }
            //for循环结束，m_ids里面要删除的线程id就走完了
            m_ids.clear();
        } 
        else if(idel = 0 &&cur <m_maxThread){
            // 新建线程
            thread t(&ThreadPool::worker,this);
            //注意线程对象不允许拷贝。 thread(const thread&)=delete
            m_workers.insert(make_pair(t.get_id(), move(t))); //匿名对象，在从容器中弹出时候销毁！
            m_curThread++;
            m_idleThread++;
        }

    }
}

void ThreadPool::worker(void){
    //用于检查m_stop这个std::atomic<bool>类型的变量是否为false。 线程池没关闭的情况下
    while(!m_stop.load()){
        function<void(void)> task = nullptr;
        {
            //对从任务队列取数据进行上锁
            unique_lock<mutex> locker(m_queueMutex);
            // 判断任务队列是否为空
            while(m_tasks.empty() && !m_stop){
                //locker管理的互斥锁会被解锁  阻塞在这， 如果有资源notify_one后就会自身解锁
                m_condition.wait(locker);  
                //假如前面是 notify_all 然后多个线程解锁 但是任务队列资源不够分,  所以加 循环 判断任务队列是否为空
                //如果是notify_one 只唤醒1个线程 用if也可以
                if(m_exitThread>0){
                    m_curThread--;
                    m_idleThread--;
                    m_exitThread--;
                    cout<<"---------- Thread exit ID: "<<this_thread::get_id()<<endl;
                    lock_guard<mutex> lock(m_idsMutex);
                    m_ids.emplace_back(this_thread::get_id());
                    return;
                }
            }

            // 从任务队列取数据
            if(!m_tasks.empty()){
                //不发生复制，把资源转移过去
                cout<<"id:"<<this_thread::get_id()<<"   Take out a task... "<<endl;
                task= move(m_tasks.front());
                m_tasks.pop();
            }
        }
        
        if(task){
            m_idleThread--;
            task();
            m_idleThread++;
        }

    }
}





int calc(int x, int y)
{
    int res = x + y;
    //cout << "res = " << res << endl;
    this_thread::sleep_for(chrono::seconds(2));
    return res;
}

int main()
{
    ThreadPool pool(4);
    vector<future<int>> results;

    for (int i = 0; i < 10; ++i)
    {
        // auto obj = bind(calc, i ,i*2);
        results.emplace_back(pool.addTask(calc, i ,i*2));
        // pool.addTask(obj);
    }

    //同步线程池： 提交任务时，调用者会等待任务执行完成，并直接获取任务的执行结果。调用者在任务完成之前会被阻塞。
    //异步线程池： 当提交任务时，调用者不会等待任务执行完成，而是立即返回。任务的执行是在后台线程中异步进行的。


    
    // //阻塞线程
    // getchar();
    // 等待并打印结果
    for (auto&& res : results)
    {
        cout << "Thread function return value: " << res.get() << endl;
    }

    return 0;
}


///g++ ThreadPool.cpp -o ThreadPool -lpthread